package models

import (
	//"fmt"

	"github.com/BPing/aliyun-live-go-sdk/client"
	"github.com/BPing/aliyun-live-go-sdk/device/live"

	"crypto/hmac"
	"crypto/sha1"
	"encoding/json"
	"io/ioutil"
	"math/rand"
	"strconv"
	"time"

	"log"
	"net/http"
	"net/url"

	"sort"

	_ "github.com/go-sql-driver/mysql"
)

/*
调用阿里云的云直播API，取得在线人数
https://helpcdn.aliyun.com/document_detail/35412.html
注意：
    URL的多个提交值以字典方式排序
    取得签名值，给URL签名
*/

func init() {
	//init
}

type Stu_Aliyun_Src struct {
}

type Stu_Aliyun_ZhiBo struct {
	Action                  string
	AccessKeyId             string
	AccessKeySecret         string
	Format                  string
	Version                 string
	Signature               string
	SignatureMethod         string
	SignatureNonce          string
	SignatureVersion        string
	Timestamp               string
	LiveStreamOnlineUserNum live.OnlineInfoResponse
}

type stu_LiveStreamOnlineUserNumInfo struct {
	LiveStreamOnlineUserNumInfo []struct {
		StreamUrl  string // 	直播流的URL
		UserNumber int    //直播流的在线人数
		Time       string //统计时刻 UTC时间
	}
}
type stu_LiveStreamOnlineUserNum struct {
	TotalUserNumber int64                           //所有流的用户数总和
	OnlineUserInfo  stu_LiveStreamOnlineUserNumInfo //每条直播流的用户数信息
	RequestId       string
}

func (this *Stu_Aliyun_ZhiBo) Init() {
	this.Format = "JSON"
	this.Version = "2016-11-01"
	this.AccessKeyId = "LTAIuTd53I4mVQUq"
	this.AccessKeySecret = "eXZQVDC2hOW4aWQLxFLd5qkOgmAu1v"
	this.SignatureMethod = "HMAC-SHA1"
	this.SignatureVersion = "1.0"
	//subhour, _ := time.ParseDuration("-5m")
	//时间改为5分钟之前
	this.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z") //请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为：YYYY-MM-DDThh:mm:ssZ。例如，2014-11-11T12:00:00Z（为北京时间2014年11月11日20点0分0秒）
	//log.Println("传入时间：", this.Timestamp)
	this.SignatureNonce = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63(), 10) //唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值

}

func (this *Stu_Aliyun_ZhiBo) Get1(domainName string) (err error) {
	//调用阿里去直播SDK
	this.AccessKeyId = "LTAIuTd53I4mVQUq"
	this.AccessKeySecret = "eXZQVDC2hOW4aWQLxFLd5qkOgmAu1v"
	cert := client.NewCredentials(this.AccessKeyId, this.AccessKeySecret)
	liveM := live.NewLive(cert, domainName, "live", nil) //.SetDebug(true)
	//resp := make(map[string]interface{})
	//liveM.StreamsPublishList(time.Now().Add(-time.Hour*12), time.Now(), &resp)
	//fmt.Println(resp)

	resp1 := live.OnlineInfoResponse{}
	err = liveM.StreamOnlineUserNum("ccnu", &resp1) //video-name是：RTMP格式:rtmp://l.kjdll.com/app-name/video-name
	log.Println("err:", err, "在线人数：", resp1)
	this.LiveStreamOnlineUserNum.TotalUserNumber = resp1.TotalUserNumber
	return err
}

func (this *Stu_Aliyun_ZhiBo) GetOnlineUserNum(domainName string) (err error) {
	var (
		//vv      map[string]string
		sortKey      []string
		mvalues      url.Values
		StringToSign string
	)
	mvalues = url.Values{}
	this.Action = "DescribeLiveStreamOnlineUserNum"
	this.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z") //请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为：YYYY-MM-DDThh:mm:ssZ。例如，2014-11-11T12:00:00Z（为北京时间2014年11月11日20点0分0秒）
	log.Println("生成当前时间：", this.Timestamp)
	this.SignatureNonce = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63(), 10) //唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值
	mvalues.Add("AccessKeyId", this.AccessKeyId)
	mvalues.Add("Action", this.Action)
	mvalues.Add("DomainName", domainName)
	mvalues.Add("Format", this.Format)
	mvalues.Add("SignatureMethod", this.SignatureMethod)
	mvalues.Add("SignatureNonce", this.SignatureNonce)
	mvalues.Add("SignatureVersion", this.SignatureVersion)
	mvalues.Add("Timestamp", this.Timestamp)
	mvalues.Add("Version", this.Version)

	StringToSign = "GET&/"

	for k := range mvalues {
		sortKey = append(sortKey, k)
	}
	sort.Strings(sortKey) //排序
	for _, v := range sortKey {
		StringToSign = StringToSign + "&" + v + "=" + mvalues.Get(v)
	}
	log.Println("StringToSign:", url.QueryEscape(StringToSign))

	//签名机验证
	//vSha1 := sha1.New()
	//io.WriteString(vSha1, this.AccessKeyId)
	key := []byte(this.AccessKeySecret + "&")
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(url.QueryEscape(StringToSign))) //将要签名的URL写入hmac
	//求出签名值
	this.Signature = string(mac.Sum(nil))
	//log.Printf("签名值 ：%x", mac.Sum(nil)) ////签名值
	//将签名写入URL
	URL := url.QueryEscape(StringToSign + "&" + "Signature" + this.Signature)
	log.Println("生成的url:", URL)

	//进行http get请求，测试结果
	resp, err := http.Get(URL)
	if err != nil {
		// handle error
		log.Println("http.Get出错！,err:", err)
	}

	defer resp.Body.Close()

	//log.Println("返回http状态码：", resp.StatusCode)
	if resp.StatusCode == 200 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			// handle error
			log.Println(" ioutil.ReadAll(resp.Body)出错！,err:", err)
		}
		log.Println("阿里API返回：\n", string(body))
		//var ss stu_LiveStreamOnlineUserNum
		err = json.Unmarshal(body, &this.LiveStreamOnlineUserNum)
		if err != nil {
			log.Println("解析数据转为结构体时出错：", err)
			return err
		}
		log.Println("在线总人数：", this.LiveStreamOnlineUserNum.TotalUserNumber)
		//log.Println("当前流的在线总人数：", ss.OnlineUserInfo[0].UserNumber)
	} else {
		log.Println("调用API出错，返回数据：")
		return err
	}

	return err
}

func (this *Stu_Aliyun_ZhiBo) GetOnlineUserNum1(domainName string) (err error) {
	var (
		mvalues url.Values
		murl    *url.URL
	)
	//log.Println("使用URL和Values")
	this.Action = "DescribeLiveStreamOnlineUserNum"
	murl, err = url.Parse("https://live.aliyuncs.com")
	if err != nil {
		//log.Println("解析url有错误 ：", err)
		return err
	}
	//log.Printf("URL：%s，URL编码：%s", murl.String(), url.PathEscape(murl.String()))
	mvalues = url.Values{}
	this.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z") //请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为：YYYY-MM-DDThh:mm:ssZ。例如，2014-11-11T12:00:00Z（为北京时间2014年11月11日20点0分0秒）
	log.Println("生成当前时间：", this.Timestamp)
	this.SignatureNonce = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63(), 10) //唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值
	mvalues.Add("AccessKeyId", this.AccessKeyId)
	mvalues.Add("Action", this.Action)
	mvalues.Add("DomainName", domainName)
	mvalues.Add("Format", this.Format)
	mvalues.Add("SignatureMethod", this.SignatureMethod)
	mvalues.Add("SignatureNonce", this.SignatureNonce)
	mvalues.Add("SignatureVersion", this.SignatureVersion)
	mvalues.Add("Timestamp", this.Timestamp)
	mvalues.Add("Version", this.Version)
	//log.Printf("Values输出：%s", mvalues)
	//log.Printf("Values Encode编码输出：%s", mvalues.Encode()) //把timestamp里的:号格式化了，不能够用作string输出
	log.Printf("URL：%s \n", murl.String())
	//将Values加入到URl中
	murl, err = url.Parse("https://live.aliyuncs.com?" + mvalues.Encode())
	if err != nil {
		log.Println("url.Parse出错！,err:", err)
	}
	//murl.RawQuery = mvalues.Encode()
	//log.Println("url  Scheme:", murl.Scheme)
	//log.Println("url Opaque:", murl.Opaque)
	log.Println("RawQuery :", murl.RawQuery)
	log.Printf("将Values加入到URl中后的URL：%s \n", murl.String())

	//签名机验证
	//vSha1 := sha1.New()
	//io.WriteString(vSha1, this.AccessKeyId)
	key := []byte(this.AccessKeySecret + "&")
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte("GET&/&" + murl.RawQuery)) //将要签名的URL写入hmac
	log.Println("计算签名的stringToSign字符串：", "GET&/&"+murl.RawQuery)
	//求出签名值
	this.Signature = string(mac.Sum(nil))
	//log.Printf("签名值 ：%x", mac.Sum(nil)) ////签名值

	//将签名写入URL
	mvalues.Add("Signature", this.Signature)
	//将Values加入到URl中
	//murl.RawQuery = mvalues.Encode() //Encode方法将v编码为url编码格式(“bar=baz&foo=quux”)，编码时会以键进行排序。
	murl, err = url.Parse("https://live.aliyuncs.com?" + mvalues.Encode())
	if err != nil {
		log.Println("url.Parse出错！,err:", err)
	}
	URL := murl.String() + "&Signature=" + url.QueryEscape(this.Signature)
	//log.Println("url  Scheme:", murl.Scheme)
	//log.Println("url Opaque:", murl.Opaque)
	//log.Printf("URL：%s \n", murl.String()) //, url.PathEscape(murl.String()))
	log.Println("URL:", URL)
	//得到签名后的URL：murl.String()

	//进行http get请求，测试结果
	resp, err := http.Get(URL)
	if err != nil {
		// handle error
		log.Println("http.Get出错！,err:", err)
	}

	defer resp.Body.Close()

	log.Println("返回http状态码：", resp.StatusCode)
	if resp.StatusCode == 200 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			// handle error
			log.Println(" ioutil.ReadAll(resp.Body)出错！,err:", err)
		}
		log.Println("阿里API返回：\n", string(body))
		//var ss stu_LiveStreamOnlineUserNum
		err = json.Unmarshal(body, &this.LiveStreamOnlineUserNum)
		if err != nil {
			log.Println("解析数据转为结构体时出错：", err)
			return err
		}
		log.Println("在线总人数：", this.LiveStreamOnlineUserNum.TotalUserNumber)
		//log.Println("当前流的在线总人数：", ss.OnlineUserInfo[0].UserNumber)
	} else {
		log.Println("调用API出错，返回数据：")
		return err
	}
	return err
}

func (this *Stu_Aliyun_Src) GetLiveSrc(srcType string) (src string, err error) {
	//取得阿里云直播的源地址与直播类型，src_type有：aliyun/rtmp,aliyun/m3u8,aliyun/flv
	var (
		sqlstr string
	)
	sqlstr = "select url from live_sources where deleted=0 and type=?"
	err = db.QueryRow(sqlstr, srcType).Scan(&src)
	return src, err
}
